﻿#region Using
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
#endregion Using

namespace LloydGame
{
    public class BloomImageProcessor : ImageProcessor
    {
        #region Class Fields
        protected RenderTarget2D m_bloomTarget;
        protected RenderTarget2D m_finalTarget;

        protected GaussianBlurImageProcessor m_gausBlur;

        protected DepthStencilBuffer m_bloomDepthStencil;
        protected DepthStencilBuffer m_finalDepthStencil;

        protected float m_bloomThreshold = 0.25f;
        protected float m_bloomIntensity = 1.25f;
        protected float m_colorIntensity = 1.0f;
        protected float m_bloomSaturation = 1.0f;
        protected float m_colorSaturation = 1.0f;
        #endregion Class Fields

        #region Properties
        public float bloomThreshold
        {
            get
            {
                return m_bloomThreshold;
            }
            set
            {
                m_bloomThreshold = value;
            }
        }

        public float bloomIntensity
        {
            get
            {
                return m_bloomIntensity;
            }
            set
            {
                m_bloomIntensity = value;
            }
        }

        public float colorIntensity
        {
            get
            {
                return m_colorIntensity;
            }
            set
            {
                m_colorIntensity = value;
            }
        }

        public float bloomSaturation
        {
            get
            {
                return m_bloomSaturation;
            }
            set
            {
                m_bloomSaturation = value;
            }
        }

        public float colorSaturation
        {
            get
            {
                return m_colorSaturation;
            }
            set
            {
                m_colorSaturation = value;
            }
        }

        public float blurAmount
        {
            get
            {
                return m_gausBlur.blurAmount;
            }
            set
            {
                m_gausBlur.blurAmount = value;
            }
        }
        #endregion Properties

        // constructor
        public BloomImageProcessor(Game p_game, int p_imageWidth, int p_imageHeight)
            : base(p_game, p_imageWidth, p_imageHeight)
        {
            m_bloomTarget = new RenderTarget2D(
                p_game.GraphicsDevice,
                p_imageWidth / 2,
                p_imageHeight / 2,
                1,
                SurfaceFormat.Color);

            m_finalTarget = new RenderTarget2D(
                p_game.GraphicsDevice,
                p_imageWidth,
                p_imageHeight,
                1,
                SurfaceFormat.Color);

            m_bloomDepthStencil = new DepthStencilBuffer(
                m_bloomTarget.GraphicsDevice,
                m_bloomTarget.Width,
                m_bloomTarget.Height,
                m_bloomTarget.GraphicsDevice.DepthStencilBuffer.Format,
                m_bloomTarget.MultiSampleType,
                m_bloomTarget.MultiSampleQuality);

            m_finalDepthStencil = new DepthStencilBuffer(
                m_finalTarget.GraphicsDevice,
                m_finalTarget.Width,
                m_finalTarget.Height,
                m_finalTarget.GraphicsDevice.DepthStencilBuffer.Format,
                m_finalTarget.MultiSampleType,
                m_finalTarget.MultiSampleQuality);

            m_gausBlur = new GaussianBlurImageProcessor(p_game, p_imageWidth / 2, p_imageHeight / 2, SurfaceFormat.Color);

            m_gausBlur.blurAmount = 4.0f;

            m_effect = Game.Content.Load<Effect>("Effects\\Bloom");
        }

        // apply a blooming effect
        public Texture2D process(Texture2D p_colorTex)
        {
            m_effect.CurrentTechnique = m_effect.Techniques["Bloom"];

            // extract a bloom texture by bright passing the color texture
            m_effect.Parameters["bloomThreshold"].SetValue(m_bloomThreshold);

            m_effect.Parameters["colorTex"].SetValue(p_colorTex);

            Game.GraphicsDevice.SetRenderTarget(0, m_bloomTarget);

            m_depthStencil = m_bloomDepthStencil;

            processPass(0);

            // blur the bloom texture
            Game.GraphicsDevice.SetRenderTarget(0, null);

            Texture2D bloomTex = m_gausBlur.process(m_bloomTarget.GetTexture());

            // combine the bloom texture with the color texture
            m_effect.Parameters["bloomIntensity"].SetValue(m_bloomIntensity);
            m_effect.Parameters["colorIntensity"].SetValue(m_colorIntensity);

            m_effect.Parameters["bloomSaturation"].SetValue(m_bloomSaturation);
            m_effect.Parameters["colorSaturation"].SetValue(m_colorSaturation);

            m_effect.Parameters["bloomTex"].SetValue(bloomTex);

            Game.GraphicsDevice.SetRenderTarget(0, m_finalTarget);

            m_depthStencil = m_finalDepthStencil;

            processPass(1);

            Game.GraphicsDevice.SetRenderTarget(0, null);

            return m_finalTarget.GetTexture();
        }
    }
}
